"""
Copyright (c) 2022 Huawei Technologies Co.,Ltd.

openGauss is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:

          http://license.coscl.org.cn/MulanPSL2

THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
"""
"""
Case Type   : 数据库系统
Case Name   : most_available_sync字段值配置off，备机同步失败时，阻塞主机。
Create At   : 2020-6-24
Owner       : @peilinqian
Description :
    1、修改most_available_sync字段值为off
    2、创建表
    3、kill备机数据库
    4、主机执行插入SQL
    5、主机进行查询
    6、重启备机
    7、再次进行查询
Expect      :
    1、修改most_available_sync字段值为off，设置成功
    2、创建表成功
    3、kill备机数据库成功
    4、主机执行插入SQL阻塞
    5、主机进行查询，15s内无返回
    6、重启备机，重启成功，步骤4阻塞事务执行成功
    7、再次进行查询，返回成功
History     :
    2021/10/19 modified by @peilinqian 因版本变更导致步骤5预期变化，修改脚本；
    逻辑变更：旧版本是csn提交之后再去等待备机同步，新版本是备机同步之后再去提交csn
"""

import time
import unittest

from testcase.utils.ComThread import ComThread
from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.CommonSH import RestartDbCluster
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import Node


class MyTest(unittest.TestCase):
    nodes_tuple = ('PrimaryDbUser', 'Standby1DbUser', 'Standby2DbUser')

    @RestartDbCluster(*nodes_tuple)
    def setUp(self):
        self.log = Logger()
        self.log.info('----Opengauss_Reliability_Db_System_Case011 start----')
        self.pri_root = Node(node='PrimaryRoot')
        self.dbUserNode = Node(node='PrimaryDbUser')
        self.sta_1_root = Node(node='Standby1Root')
        self.sta_2_root = Node(node='Standby2Root')
        self.pri_sh = CommonSH('PrimaryDbUser')
        self.com = Common()
        self.constant = Constant()
        self.t_name = 'tb_Dbsys_Case011'
        self.node_num = self.com.get_node_num(self.pri_root)
        self.log.info(self.node_num)
        self.max_time = 1200
        self.min_time = 300

    def test_main(self):
        step_txt = '----查询原参数配置值----'
        self.log.info(step_txt)
        result = self.pri_sh.executDbSql('show most_available_sync;')
        self.log.info(f"most_available_sync is {result}")
        self.para1 = result.strip().splitlines()[-2]
        result = self.pri_sh.executDbSql('show synchronous_commit;')
        self.log.info(f"synchronous_commit is {result}")
        self.para2 = result.strip().splitlines()[-2]

        step_txt = '----step1:修改参数most_available_sync值为off; expect:设置成功----'
        self.log.info(step_txt)
        mod_msg = self.pri_sh.executeGsguc('set',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'most_available_sync = off')
        self.log.info(mod_msg)
        self.assertTrue(mod_msg, '执行失败:' + step_txt)
        mod_msg = self.pri_sh.executeGsguc('set',
                                           self.constant.GSGUC_SUCCESS_MSG,
                                           'synchronous_commit = on')
        self.log.info(mod_msg)
        self.assertTrue(mod_msg, '执行失败:' + step_txt)

        # 重启数据库配置文件生效
        self.pri_sh.stopDbCluster()
        time.sleep(2)
        self.pri_sh.startDbCluster()
        self.log.info('----查看主机query，同步是否正常----')
        self.pri_sh.check_location_consistency('primary',
                                               self.node_num,
                                               self.min_time)
        self.log.info('----查询主备状态----')
        status = self.pri_sh.getDbClusterStatus('status')
        self.assertTrue(status, '执行失败:' + step_txt)

        step_txt = '----step2:创建表; expect:创建成功----'
        self.log.info(step_txt)
        sql = f'drop table if exists {self.t_name};' \
            f'create table {self.t_name}(t_id int, t_desc text);'
        self.log.info(sql)
        msg = self.pri_sh.executDbSql(sql)
        self.log.info(msg)
        self.assertIn(self.constant.TABLE_CREATE_SUCCESS, msg,
                      '执行失败:' + step_txt)

        step_txt = '----step3:kill备机数据库; expect:kill成功----'
        self.log.info(step_txt)
        msg = self.com.kill_pid(self.sta_1_root, 9)
        self.assertEqual(msg, '', '执行失败:' + step_txt)
        msg = self.com.kill_pid(self.sta_2_root, 9)
        self.assertEqual(msg, '', '执行失败:' + step_txt)
        db_status = self.pri_sh.getDbClusterStatus('status')
        self.assertFalse(db_status, '执行失败:' + step_txt)

        step_txt = '----step4:主机执行插入SQL; expect:阻塞----'
        self.log.info(step_txt)
        insert_cmd = f'insert into {self.t_name} values(1, \'ddd\');'
        insert_thread = ComThread(self.pri_sh.executDbSql, args=(insert_cmd,))
        insert_thread.setDaemon(True)
        insert_thread.start()
        time.sleep(5)

        step_txt = '----step5:主主机进行查询; expect:15s内无返回----'
        self.log.info(step_txt)
        select_cmd = f'select * from {self.t_name};'
        select_thread = ComThread(self.pri_sh.executDbSql, args=(select_cmd,))
        select_thread.setDaemon(True)
        select_thread.start()
        select_thread.join(15)
        select_result = select_thread.get_result()
        self.log.info(select_result)
        self.assertEqual(None, select_result, '执行失败:' + step_txt)

        step_txt = '----step6:重启备机; expect：重启成功，步骤4阻塞事务执行成功----'
        self.log.info(step_txt)
        msg = self.pri_sh.startDbCluster()
        self.assertTrue(msg, '执行失败:' + step_txt)
        self.log.info('----查询主备状态----')
        status = self.pri_sh.getDbClusterStatus('status')
        self.assertTrue(status, '执行失败:' + step_txt)
        self.log.info('----查询步骤4阻塞事务执行情况----')
        insert_thread.join()
        insert_result = insert_thread.get_result()
        self.log.info(insert_result)
        self.assertIn('INSERT', insert_result, '执行失败:' + step_txt)

        step_txt = '----step7:再次进行查询; expect：返回成功----'
        self.log.info(step_txt)
        select_cmd = f'select * from {self.t_name};'
        select_result = self.pri_sh.executDbSql(select_cmd)
        self.log.info(select_result)
        self.assertIn('1 row', select_result, '执行失败:' + step_txt)

    def tearDown(self):
        self.log.info('----this is teardown----')
        step_txt = '----还原参数----'
        self.log.info(step_txt)
        self.pri_sh.executeGsguc('reload',
                                 self.constant.GSGUC_SUCCESS_MSG,
                                 f'most_available_sync = {self.para1}')
        self.pri_sh.executeGsguc('reload',
                                 self.constant.GSGUC_SUCCESS_MSG,
                                 f'synchronous_commit = {self.para2}')

        step_txt = '----清理测试表数据----'
        self.log.info(step_txt)
        sql = f'drop table if exists {self.t_name};'
        self.log.info(sql)
        msg = self.pri_sh.executDbSql(sql)
        self.log.info(msg)

        self.log.info('----Opengauss_Reliability_Db_System_Case011 end----')
